from flask import request
from flask_socketio import SocketIO, emit
import threading
import time


def create_server(app):
    """心跳检测"""
    socketio = SocketIO(app)

    clients = {}
    HEARTBEAT_INTERVAL = 5
    TIMEOUT = 10
    MAX_ATTEMPTS = 10

    @socketio.on('connect')
    def handle_connect():
        ip_address = request.remote_addr  # 获取服务端的 IP 地址
        clients[request.sid] = {
            'last_heartbeat': time.time(),
            'attempts': 0,
            'ip': ip_address
        }
        emit('response', {'message': 'Connected'})
        print(f'Client connected from IP: {ip_address}')

    @socketio.on('heartbeat')
    def handle_heartbeat():
        if request.sid in clients:
            clients[request.sid]['last_heartbeat'] = time.time()
            clients[request.sid]['attempts'] = 0
            emit('response', {'message': 'ALIVE'})

    @socketio.on('disconnect')
    def handle_disconnect():
        if request.sid in clients:
            ip_address = clients[request.sid]['ip']
            del clients[request.sid]
            print(f'Client disconnected from IP: {ip_address}')

    def check_service():
        while True:
            current_time = time.time()
            for sid, client_data in list(clients.items()):
                if current_time - client_data['last_heartbeat'] > TIMEOUT:
                    if client_data['attempts'] < MAX_ATTEMPTS:
                        # Increment attempt count and send 'ALIVE?' message
                        client_data['attempts'] += 1
                        socketio.emit('heartbeat', {'message': 'ALIVE?'}, room=sid)
                        print(f'Sent ALIVE? to {client_data["ip"]}, attempt {client_data["attempts"]}')
                    else:
                        # If attempts exceed MAX_ATTEMPTS, consider the client as dead
                        print(f'Client {client_data["ip"]} did not respond after {MAX_ATTEMPTS} attempts. Client die!')
                        del clients[sid]
            time.sleep(HEARTBEAT_INTERVAL)

    threading.Thread(target=check_service, daemon=True).start()

    return app, socketio
